using System.Text.Json.Nodes;
using FastDevTemplate.Api.Attribute;
using FastDevTemplate.DataAccess.Entities;
using FastDevTemplate.Service;
using FastDevTemplate.Service.Base.EventBus;
using FastDevTemplate.Service.Event.MessageObject;
using FastDevTemplate.Service.Interface;
using Microsoft.AspNetCore.Mvc.Controllers;

namespace FastDevTemplate.Api.Middlewares;

public static class MiddlewareExtensions
{
    public static IApplicationBuilder UseLogRecord(this IApplicationBuilder builder)
    {
        return builder.UseMiddleware<LogRecordMiddleware>();
    }
}

public class LogRecordMiddleware
{
    private readonly RequestDelegate _next;
    
    public LogRecordMiddleware(RequestDelegate next)
    {
        _next = next;
    }

    public async Task InvokeAsync(HttpContext context, ILogService logService)
    {
        // 处理请求前的逻辑
        var request = context.Request;

        var originalBodyStream = context.Response.Body;
        using var responseBody = new MemoryStream();
        context.Response.Body = responseBody;

        // 调用下一个中间件或处理程序
        await _next(context);
        
        //处理请求后的逻辑
        context.Response.Body.Seek(0, SeekOrigin.Begin);
        var endpoint = context.GetEndpoint();
        if (endpoint?.Metadata.GetMetadata<ControllerActionDescriptor>() is ControllerActionDescriptor
            controllerActionDescriptor)
        {
            var logAttribute = controllerActionDescriptor
                .MethodInfo
                .GetCustomAttributes(typeof(LogRecordAttribute), inherit: true)
                .FirstOrDefault() as LogRecordAttribute;

            if (logAttribute != null)
            {
                var uuid = request.Headers["uuid"][0];
                int stateCode = 0;
                if (context.Response.ContentType != null && context.Response.ContentType.Contains("application/json"))
                {
                    var reader = await new StreamReader(context.Response.Body).ReadToEndAsync();
                    var json = JsonNode.Parse(reader);
                    stateCode = json?["code"]?.GetValue<int>() ?? 0;
                }

                // 👇考虑使用观察者模式优化，减少请求等待时间
                if (!String.IsNullOrEmpty(uuid))
                {
                    var tokenInfo = TokenService.TryGetToken(Guid.Parse(uuid));
                    if (tokenInfo != null)
                        LocalEventBus.Publish(new UserLogMessage()
                        {
                            FromUser = tokenInfo.UserLoginDto.UserName,
                            Action = request.Path,
                            Describe = logAttribute.Describe,
                            State = stateCode == 0 ? ActionState.None :
                                stateCode > 0 ? ActionState.Successful : ActionState.Error
                        });
                }

            }

        }
        
        context.Response.Body.Seek(0, SeekOrigin.Begin);
        await responseBody.CopyToAsync(originalBodyStream);
        context.Response.Body = originalBodyStream;
    }

}